package uia.alumni.web;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import uia.alumni.data.Role;
import uia.alumni.data.User;
import uia.alumni.form.FieldType;
import uia.alumni.form.FormField;
import uia.alumni.search.Search;
import static uia.alumni.form.FieldType.*;
import static uia.alumni.web.Constants.*;

/**
 * The abstract Page class should be used as the superclass for all
 * commands that output html pages. This will enforce
 * a uniform look and feel across all html pages in the application.
 * <p>
 * Subclasses of this class must implement the writeBody() method.
 * <p>
 * This class produces pages consisting of a number of nested 
 * &lt;DIV&gt;-elements. The layout of these elements are controlled
 * by the stylesheet style.css. The ascii drawing below shows
 * the structure and the current layout.
 *
 * <pre>
 * +- wrapper ----------------------------------------------+
 * | +- banner ----------------------------+ +- loginbox--+ |
 * | |                                     | |            | |
 * | +-------------------------------------+ +------------+ |
 * | +- menu ----+ +- main -------------------------------+ |
 * | |           | | +- body ---------------------------+ | |
 * | |           | | |                                  | | |
 * | |           | | | content generated by writeBody() | | |
 * | |           | | |                                  | | |
 * | |           | | +----------------------------------+ | |
 * | |           | | +- message ------------------------+ | |
 * | |           | | |                                  | | |
 * | |           | | +----------------------------------+ | |
 * | + ----------+ +------------------------------------+ | |
 * +--------------------------------------------------------+
 * </pre>
 *
 * @author Even Aaby Larsen (even.larsen@uia.no)
 */
public abstract class Page extends Command implements Tag {

    public Page(Role requiredRole) {
        super(requiredRole);
    }

    /**
     * Sets sensible headers before calling writeBody()
     *
     * @param request DOCUMENT ME!!
     * @throws IOException DOCUMENT WHEN!!
     */
    public void execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setHeader("Content-Type", "text/html;charset=UTF-8");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Expires", "0");
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        writeHeader(out, request);
        writeWrapper(out, request);
        writeEnd(out, request);

        /* Flushes and closes the out writer */
        out.flush();
        out.close();
    }

    /**
     * Write the html document. This method is called by format, and
     * is expected to write the html code for the main content div
     * to the the PrintWriter out.
     */
    public abstract void writeBody(PrintWriter out, HttpServletRequest request);

    /**
     * Writes the start of the page, the html headers and the menu
     */
    private void writeHeader(PrintWriter out, HttpServletRequest request) {
        out.println("<html lang=en>\n" +
                "    <head>\n" +
                "    <meta charset=utf-8>\n" +
                "    <title>Mockups</title>\n" +
                "    <link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"" +
                request.getContextPath() + "/style.css\" />\n" +
                "</head>\n" +
                "<body>");
    }

    private void writeWrapper(PrintWriter out, HttpServletRequest request) {
        out.println("<div id=\"wrapper\">");
        writeLoginBox(out, request);
        writeMain(out, request);
        out.println("<h2 id=\"footer\">" + tagA(Search.SERVLET_NAME, "Search") + " | " + tagA(Home.SERVLET_NAME, "Home") + "</h2>");
        out.println("\n</div> <!-- wrapper -->");
    }

    /** writes the html code for the loginbox */
    private void writeLoginBox(PrintWriter out, HttpServletRequest request) {
        User user = (User) request.getSession().getAttribute(USER);

        out.println("\n<div id=\"loginbox\">");
        if (user == null) {
            out.println(tagForm(Login.SERVLET_NAME));
            out.println(tagField(USERNAME, TEXT));
            out.println(tagField(PASSWORD, PW));
            out.println(tagField("Login", SUBMIT));
            out.println("</form>");

        } else {
            out.println("<p>Loged in with username: " + user.getEmail() + " | ");
            out.println(tagA(Logout.SERVLET_NAME, "Logout"));
            out.println("</p>");
        }
        out.println("</div>");
    }

    /** Write the menu */
    /** Write the content part of the page */
    private void writeMain(PrintWriter out, HttpServletRequest request) {
        out.println("\n<div id=\"main\">");
        out.println("\n<div id=\"body\">");

        writeBody(out, request);
        out.println("\n</div> <!-- body -->");
        writeMessage(out, request);
        out.println("\n</div> <!-- main -->");
    }

    /** Write any error or warning messages */
    private void writeMessage(PrintWriter out, HttpServletRequest request) {
        ArrayList<String> messages = (ArrayList<String>) request.getAttribute(MESSAGES);
        if (null != messages) {
            out.println("\n<div id=\"message\">");
            for (String msg : messages) {
                out.println("<p>" + msg + "</p>");
            }
            out.println("</div> <!-- message -->");
        }
    }

    /** Write a List of Errors in a form. */
    protected void writeFormErrors(PrintWriter out, HttpServletRequest request) {
        ArrayList<FormField> errors = (ArrayList<FormField>) request.getAttribute(FORMERRORS);
        if (errors != null) {
            out.println("<h2 class=\"error\">Invalid Form, Try Again:</h2>");
            out.println("<dl class=\"error\">\n");
            for (FormField f : errors) {
                out.println(tagDD("Error Type: " + f.getFieldType().toString(),
                        "Value submitted : " + f.getFieldValue()));
            }
            out.println("</dl>\n");
        }
    }

    /**
     * Method that writes the html code to complete the page.
     */
    private void writeEnd(PrintWriter out, HttpServletRequest request) {

        out.println("\n</body>");
        out.println("</html>");
    }

    ///// TAG IMPLEMENTATION //////
    /**
     * Return a <H1> header
     * @param text
     * @return
     */
    public String tagH1(String text) {
        return "<h1>" + text + "</h1>";
    }
    public String tagH2(String text) {
        return "<h2>" + text + "</h2>";
    }
    /**
     * Return <UL> list
     * @param list
     * @return list or empty string
     */
    public String tagUl(ArrayList<String> list) {
        if (!list.isEmpty()) {
            String s = "<ul>\n";
            for (String item : list) {
                s += "     <li>" + item + "</li>\n";
            }
            s += "</ul>\n";
            return s;
        }
        return " ";
    }

    public String tagLi(String text) {
        if (!text.isEmpty()) {
            return "<li>" + text + "</li>\n";
        }
        return " ";
    }

    /**
     * <p> Tag
     * @param text
     * @return
     */
    public String tagP(String text) {
        if (!text.isEmpty()) {
            return "<p>" + text + "</p>\n";
        }
        return " ";
    }

    /**
     * <dt> <dd> tag's for <dl> list
     * @param dt
     * @param dd
     * @return
     */
    public String tagDD(String dt, String dd) {
        if (dd.isEmpty() || dd == null) {
            return " ";
        }
        String s = "<dt>" + dt + "</dt>\n";
        s += "<dd>" + dd + "</dd>\n";
        return s;
    }

    /**
     * Link Soup! Could have solved this with a Multi-dimensional Array, but
     * that made it harder to create a link. 
     * @param url
     * @param title
     * @return <a> link
     */
    public String tagA(String url, String title) {
        return tagA(url, title, null, null, null, null, null, null);
    }

    public String tagA(String url, String title, String p1, String v1) {
        return tagA(url, title, p1, v1, null, null, null, null);
    }

    public String tagA(String url, String title, String p1, String v1, String p2, String v2) {
        return tagA(url, title, p1, v1, p2, v2, null, null);
    }

    public String tagA(String url, String title, String p1, String v1, String p2, String v2, String p3, String v3) {
        String s = "<a href=\"" + url + ".do";
        if (p1 != null) {
            s += "?" + p1 + "=" + v1;
            if (p2 != null) {
                s += "&amp;" + p2 + "=" + v2;
                if (p3 != null) {
                    s += "&amp;" + p3 + "=" + v3;
                }
            }
        }
        return s += "\" title=\"" + title + "\">" + title + "</a>";
    }

    /**
     * Print the beginning of a form.
     * @param target
     * @return <form> tag
     */
    public String tagForm(String target) {
        return tagForm(target, null, null);
    }

    public String tagForm(String target, String p1, String v1) {
        String s = "<form action=\"" + target + ".do";
        if (p1 != null) {
            s += "?" + p1 + v1;
        }
        return s += "\" method=\"POST\" enctype=\"application/x-www-form-urlencoded\">\n";
    }

    /**
     *
     * @param name Name of the Field. This is used to get and retrieve values for fields.
     * @param type The field type. This defined with enum FieldType's.
     * @param label Label Name of a field. This is used with the <label> tag.
     * @param value The value of the field.
     * @return <input> or <textarea>
     */
    public String tagField(String name, FieldType type) {
        return tagField(name, type, null, null);
    }

    public String tagField(String name, FieldType type, String label, boolean bool) {
        return tagField(name, type, label, String.valueOf(bool));
    }

    public String tagField(String name, FieldType type, String label) {
        return tagField(name, type, label, null);
    }

    public String tagField(String name, FieldType type, String label, String value) {
        String s = "";
        if (label != null) {
            s += "<label>" + label + "</label>\n";
        }

        switch (type) {
            case SUBMIT:
                s += "<input name=\"" + name + "\" type=\"" + type + "\" value=\"";
                if (value != null) {
                    s += value + "\">\n";
                } else {
                    s += "Submit\">\n";
                }
                break;
            case TEXTAREA:
                s += "<br><textarea name=\"" + name + "\"  cols=\"65\" rows=\"15\">";
                if (value != null) {
                    s += value;
                }
                s += "</textarea>\n";
                break;
            case CHECKBOX:
                s += "<input name=\"" + name + "\" type=\"" + type + "\"";
                if (value.equals("true") && value != null) {
                    s += " checked ";
                }
                return s += ">\n";

            default:
                s += "<input name=\"" + name + "\" type=\"" + type + "\"";
                if (value != null) {
                    s += " value=\"" + value + "\"";
                }
                s += ">\n";
        }
        return s;
    }
    /**
     * Write a message with info for the Admin User
     */
    public String getAdminInfo() {
        String s = "<div class=\"admin\"><p><strong>You have some Admin Rights.</strong></p><p>" +
                "We trust you have received the usual " +
                "lecture from the local System Administrator." +
                " It usually boils down to these three things:</p>";
        s += "<ol>";
        s += tagLi("Respect the privacy of others.");
        s += tagLi("Think before you type.");
        s += tagLi("With great power comes great responsibility.");
        s += "</ol>";
        return s;
    }
    /*
     * Print dropdown menu selectors for a date. The output is a table row with two cells.
     * The first cell contains the prompt. The second cell contains a select element for
     * day, month and year. The name of the day selector is prefix_d, the month selector
     * prefix_m, and year prefix_y.
     *
     * @param prompt
     * @param date pre-selected value
     * @param prefix prefix used to ensure that the select controls have unique names
     */
}
